home *** CD-ROM | disk | FTP | other *** search
- /* Expire old messages.
- * Inspired by 'expire.c' by Bernie Roehl.
- * Substantially rewritten for integration into KA9Q NOS,
- * WG7J v1.01 and later
- * by Johan. K. Reinalda, WG7J/PA3DIS, March/April 92
- *
- * Old bid expiry by WG7J, March 92
- */
- /* 'expire n' sets the expire interval for n hours.
- * Each time the timer goes off, a new process is started,
- * that expires the old messages...
- *
- * The control file '~/spool/expire.dat' contains lists of
- * filename age
- *
- * where 'filename' is the name of the .txt file under '~/spool/mail'
- * containing the messages (without the .txt extension)
- * filename can be extended into subdirectories, and can have either
- * '/', '\' or '.' to indicate subdirectories.
- *
- * 'age' is an integer giving the maximum age of a message in days,
- * after which expiry is performed.
- * If no age is given, the default age is 21 days.
- *
- */
- #include "global.h"
- #include "commands.h"
- #include "files.h"
- #ifdef MSDOS
- #include <dir.h>
- #include <dos.h>
- #else
- #include "ctype.h"
- #include <time.h>
- #include <sys/stat.h>
- #endif
- #include "timer.h"
- #include "proc.h"
- #include "bm.h"
- #include "delegate.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: expire.c,v 1.27 1997/09/07 21:18:28 root Exp root $";
- #endif
-
- int ExpireActive = 0;
- char *ExpireArea = NULLCHAR;
- time_t ExpireLast = 0;
- extern char *nntp_name_expansion (char *name);
- extern void updateCtl (const char *who, struct let * info);
- extern int expired;
-
-
- static time_t j_mktime (struct tm *);
-
- /* If you're using BC++ 2.0 or higher, you don't need this,
- * but TCC 2.0 doesn't have it...
- */
- /* Simple emulation of the mktime() call (sort-of works :-) )
- * doesn't do any error checking,
- * no timezone adjustments or value adjustments
- * neglects seconds,
- * and might be off by a day for leap year corrections
- * Simply 'sort-a' calculates the number of seconds since 1970 - WG7J
- */
- time_t
- j_mktime (t)
- struct tm *t;
- {
- static int total[12] =
- {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
- int years;
- int leapyears;
- int days;
-
- /* time count start at jan 1, 1970, 00:00 hrs */
- years = t->tm_year - 70;
- /* adjust in case year was passed in as 19xx, instead of xx */
- if (years >= 1900)
- years -= 1900;
- /* adjust for leap-years */
- leapyears = (years + 2) / 4;
- if (!((years + 70) & 3) && (t->tm_mon < 2))
- --leapyears;
-
- #ifdef linux
- days = years * 365L + leapyears + total[t->tm_mon] + (t->tm_mday - 1);
- return (days * 86400L + t->tm_hour * 3600L + t->tm_min * 60L + t->tm_sec);
- #else
- days = years * 365L + leapyears + total[t->tm_mon] + t->tm_mday;
- return (days * 86400L + t->tm_hour * 3600L + t->tm_min * 60L - 19 * 3600L);
- #endif
- }
-
-
-
- #if (defined(EXPIRY) || defined(DELEGATE))
-
- /* Default expiry values: */
- #define DEFAULT_AGE 21 /* 21 days from arrival date */
- #define MSPHOUR (1000L*60L*60L)
- static struct timer Expiretimer;
- extern int PruneAge;
-
- static void Expireprocess (int a, void *v1, void *v2);
- void Expiretick (void *);
- void expire (char *, int);
-
-
- int
- doexpire (int argc, char **argv, void *p OPTIONAL)
- {
- if (argc < 2) {
- tprintf ("timer: %lu/%lu hrs\n", read_timer (&Expiretimer) / MSPHOUR,
- dur_timer (&Expiretimer) / MSPHOUR);
- return 0;
- }
- if (*argv[1] == 'n') {
- Expiretick (NULL);
- return 0;
- }
- /* set the timer */
- stop_timer (&Expiretimer); /* Just in case */
- Expiretimer.func = (void (*)(void *)) Expiretick; /* what to call on timeout */
- Expiretimer.arg = NULL; /* dummy value */
- set_timer (&Expiretimer, atol (argv[1]) * MSPHOUR); /* set timer duration */
- start_detached_timer (&Expiretimer);
- return 0;
- }
-
-
-
- void
- Expiretick (void *p OPTIONAL)
- {
- start_detached_timer (&Expiretimer);
- /* Spawn off the process */
- if (!ExpireActive)
- if (newproc ("Expiry", 2048, Expireprocess, 0, NULL, NULL, 0) == NULLPROC)
- log (-1, "Couldn't start Expiration process");
- }
-
-
-
- static void
- Expireprocess (int a OPTIONAL, void *v1 OPTIONAL, void *v2 OPTIONAL)
- {
- char line[80];
- int age = DEFAULT_AGE;
- char *cp;
- FILE *ctl;
-
- ExpireActive = 1;
- log (-1, "EXPIRE process started");
- #ifdef DELEGATE
- purge_delegate ();
- #endif
- setMaintenance ();
- if ((ctl = fopen (Expirefile, "r")) != NULLFILE) {
- (void) time (&ExpireLast);
- /* read lines from the control file */
- while (fgets (line, sizeof (line), ctl) != NULLCHAR) {
- kwait (NULL); /* be nice */
- if ((*line == '#') || (*line == '\n')) /* comment or blank line */
- continue;
- rip (line);
- age = DEFAULT_AGE;
- /* terminate area name */
- if ((cp = strpbrk (line, " \t")) != NULLCHAR) {
- /* there is age info */
- *cp++ = '\0';
- age = atoi (cp);
- if (age <= 0)
- age = DEFAULT_AGE;
- }
- kwait (NULL); /* be nice */
- ExpireArea = line; /*lint !e789 */
- (void) nntp_name_expansion (line);
- expire (line, age);
- ExpireArea = NULLCHAR;
- }
- (void) fclose (ctl);
- }
- clearMaintenance ();
- log (-1, "EXPIRE process completed");
- ExpireActive = 0;
- }
-
-
-
- void
- expire (char *filename, int age)
- {
- char file[128], bckfile[128], bckctl[128], *cp;
- char buf[128];
- int keep, copy, kept = 0;
- FILE *old;
- FILE *new;
- long pos;
- time_t now;
- time_t then;
- struct tm t;
- struct let lt;
- int entrynum = 1;
- int ctlfound = 0;
-
- if (age == -1)
- age = PruneAge;
- /* first replace all '.' and '\' with '/' */
- for (cp = filename; *cp != '\0'; cp++)
- if ((*cp == '.') || (*cp == '\\'))
- *cp = '/';
-
- if (mlock (Mailspool, filename)) {
- /* can't get a lock */
- return;
- }
- /* rename the old *.ctl file */
- sprintf (file, "%s/control/%s.ctl", Mailspool, filename);
- sprintf (bckctl, "%s/control/%s.exp", Mailspool, filename);
- unlink (bckctl);
- if (rename (file, bckctl) != -1)
- ctlfound = 1;
-
- /* now append the 'home dir' in front of name */
- sprintf (file, "%s/%s", Mailspool, filename);
-
- /* get the name for the backup file */
- sprintf (bckfile, "%s.exp", file);
- strcat (file, ".txt");
-
- /* rename the file */
- unlink (bckfile);
- if (rename (file, bckfile) == -1) {
- rmlock (Mailspool, filename);
- return;
- }
- kwait (NULL);
- /* open the backup file and the new txt file */
- if ((old = fopen (bckfile, READ_TEXT)) == NULLFILE) {
- rmlock (Mailspool, filename);
- return;
- }
- if (!ctlfound && filelength(fileno(old)) == 0) {
- (void) fclose (old);
- unlink (bckfile);
- rmlock (Mailspool, filename);
- log (-1, "Expire: removing empty file for area %s", filename);
- return;
- }
- if ((new = fopen (file, WRITE_TEXT)) == NULLFILE) {
- rmlock (Mailspool, filename);
- return;
- }
- kwait (NULL);
- (void) time (&now);
- copy = expired = 0;
- pos = ftell (old);
- while (fgets (buf, sizeof (buf), old) != NULLCHAR) {
- kwait (NULL);
- if (!strncmp (buf, "From ", 5)) {
- /* start of next message; at this point
- * pos has the offset of the start of this line
- */
- keep = copy = 0;
- while (fgets (buf, sizeof (buf), old) != NULLCHAR) {
- kwait (NULL);
- if (*buf == '\n')
- break; /* end of headers */
- if (htype (buf) == DATE) {
- /* find age from ARPA style date */
- /* check to see if there is a "Day, " field */
- if ((cp = strchr (buf, ',')) != NULLCHAR) {
- /* probably standard ARPA style header */
- cp = &buf[11]; /* get past header and DAY field */
- } else {
- /* probably a NNTP style message, that has no
- * "Day, " part in the date line
- */
- cp = &buf[6];
- }
- /* now we should be at the start of the
- * "14 Apr 92 08:14:32" string
- */
- if (strlen (cp) < 17) /* Too short */
- break;
- t.tm_mday = atoi (cp);
- if (*(++cp) != ' ')
- ++cp;
- ++cp;
- for (t.tm_mon = 0; t.tm_mon < 12; t.tm_mon++)
- if (strnicmp (Months[t.tm_mon], cp, 3) == 0)
- break;
- if (t.tm_mon == 12)
- break; /* invalid */
- #if 1
- /* modified to accept either
- * "14 Apr 92 08:14:32" string or
- * "14 Apr 1992 08:14:32" string
- * WA3DSP 11/94 - modified by KO4KS
- */
-
- while (*cp != ' ')
- ++cp;
- ++cp;
- t.tm_year = atoi (cp);
- if (t.tm_year > 99)
- t.tm_year %= 100;
-
- while (*cp != ' ')
- ++cp;
- ++cp;
- t.tm_hour = atoi (cp);
- t.tm_min = atoi (cp + 3);
- t.tm_sec = atoi (cp + 6);
-
- #else
- t.tm_year = atoi (cp + 4);
- t.tm_hour = atoi (cp + 7);
- t.tm_min = atoi (cp + 10);
- t.tm_sec = atoi (cp + 13);
- #endif
- if ((then = j_mktime (&t)) == (time_t) -1)
- break; /* invalid, delete */
- /* Now check against age */
- if (now - then < (time_t) (age * 86400L))
- keep = 1;
- break;
- }
- }
- statusCtl (filename, "exp", <, entrynum, 1);
- if (!keep && (lt.status & BM_PERMANENT))
- keep = 1; /* don't expire permanent messages */
- if (keep) {
- /* rewind to start of this message,
- * write from-line and copy the rest
- */
- kwait (NULL);
- if (lt.status & BM_DELETE)
- expired++;
- else {
- lt.start = ftell (new);
- updateCtl (filename, <);
- fseek (old, pos, SEEK_SET);
- (void) fgets (buf, sizeof (buf), old);
- fputs (buf, new);
- copy = 1;
- kept++;
- }
- } else
- expired++;
- entrynum++;
- } else { /* Any none 'from' line */
- if (copy)
- /* we're in the middle of copying a message */
- fputs (buf, new);
- }
- kwait (NULL);
- pos = ftell (old);
- }
- (void) fclose (old);
- (void) fclose (new);
- kwait (NULL);
- unlink (bckfile);
- unlink (bckctl);
- rmlock (Mailspool, filename);
- if (expired)
- log (-1, "Expired: %d in %s", expired, filename);
-
-
- if (!kept) {
- log (-1, "Expire: removing empty file for area %s", filename);
- sprintf (file, "%s/%s.txt", Mailspool, filename);
- unlink (file);
- }
- }
-
-
- #endif /* EXPIRY */
-